#include "adr_trigger.h"

#include "data_cache.h"
#include "public_define.h"
#include "filemanagercommand.h"
#include <typeinfo>
#include "special_trigger.h"
#include "common_opr_all.h"
#include "tool.h"
#include "ktime.h"

using namespace DcAdr;

AdrTrigger::AdrTrigger()
{
    m_protoParse.initProto();
    try
    {
        m_protoParse.parseTriggerConfigJsonData(global_data::g_collect_config_buf);
    }
    catch (const std::exception &e)
    {
        Log_ERROR("trow exception: {}", e.what());
    }
}

AdrTrigger::~AdrTrigger()
{
}

AdrTrigger &AdrTrigger::getInstance()
{
    static AdrTrigger adr;
    return adr;
}

bool AdrTrigger::protoRuleContainTopic(const std::string &topic)
{
    return m_protoParse.protoRuleContainTopic(topic);
}

template <typename retT>
retT AdrTrigger::getProtoMessageMemberValue(google::protobuf::Message &message, const std::queue<std::string> &protoStruct)
{
    try
    {
        /* code */
        std::queue<std::string> protoStructNew = protoStruct;
        Json::Value value = ProtoMemberToJsonValue(message, protoStructNew);
        // Log_Info("ProtoMessageMemberValue Json::Value: {}", value.toStyledString());
        if (value.is<retT>())
        {
            return value.as<retT>();
        }
        else
        {
            return retT();
        }
    }
    catch(const std::exception& e)
    {
       Log_Info("gd Exception json value3 ERROR: {}", e.what());
    }
    return retT();

    
}

//获取相关message的成员的value
Json::Value AdrTrigger::ProtoMemberToJsonValue(const google::protobuf::Message &message, std::queue<std::string> &protoStruct)
{
    const google::protobuf::Descriptor *des = message.GetDescriptor();
    const google::protobuf::Reflection *ref = message.GetReflection();
    if (nullptr == des)
    {
        Log_ERROR("Proto Descriptor is nullptr");
        return Json::Value();
    }
    if (nullptr == ref)
    {
        Log_ERROR("Proto Reflection is nullptr");
        return Json::Value();
    }
    // Log_Info("Message type: {}", message.GetTypeName());

    if (protoStruct.empty())
    {
        Log_ERROR("proto name queue empty.");
        return Json::Value();
    }
    //为了兼容嵌套message,获取首个判断
    std::queue<std::string> nameQueue = protoStruct;
    std::string name = nameQueue.front();
    nameQueue.pop();

    for (int i = 0; i < des->field_count(); i++)
    {
        const google::protobuf::FieldDescriptor *field = des->field(i); //      field 相当于此message下的信号， field->name(): 信号名
        // Log_Info("field row, real name: {}  name: {}  - {}", name, field->name(), field->DebugString());
        if (field == nullptr)
        {
            continue;
        }
        ///判断信号名
        if (field->name() != name)
        {
            continue;
        }
        if (field->is_repeated()) //不需要数组，数组需要单独的解析
        {
            continue;
        }
        switch (field->cpp_type())
        {
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32:
        {
            return ref->GetInt32(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64:
        {
            return ref->GetInt64(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32:
        {
            return ref->GetUInt32(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64:
        {
            return ref->GetUInt64(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_DOUBLE:
        {
            return ref->GetDouble(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_FLOAT:
        {
            return ref->GetFloat(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL:
        {
            return ref->GetBool(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_ENUM:
        {
            return ref->GetEnumValue(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING:
        {
            return ref->GetString(message, field);
        }
        break;
        case google::protobuf::FieldDescriptor::CppType::CPPTYPE_MESSAGE:
        {
            //先判断是不是嵌套message，如果是，嵌套获取
            return ProtoMemberToJsonValue(ref->GetMessage(message, field), nameQueue);
        }
        break;
        default:
            break;
        }
    }
    return Json::Value();
}

//设置触发时间。在trigger进行条件表达式判断前，看这个事件是否是在limit时间后才允许再次进入条件表达式，进行触发。
void AdrTrigger::settrigLaterTime(const std::string &eventId)
{
    if (NotContain_Map(m_protoParse.m_protoRuleList, eventId))
    {
        return;
    }

    std::shared_ptr<ProtoCondInfo_t> protoInfo = m_protoParse.m_protoRuleList[eventId];
    if (protoInfo != nullptr)
    {
        protoInfo->trigLaterTime = Util::getMsTime();
    }
}

uint8_t AdrTrigger::getEventLevl(const std::string &eventId)
{
    uint8_t level = 6;
    if (Contain_Map(m_protoParse.m_protoRuleList, eventId))
    {
        level = m_protoParse.m_protoRuleList[eventId]->level;
        switch (level)
        {
        case 1:
        case 2:
        case 3:
        case 4:
		case 5:
		case 6:
        {
            /* code */
            break;
        }
        default:
        {
            level = 6;
            Log_Info("EventLevl config is error; eventId:{}", eventId);
            break;
        }
        }
    }
    return level;
}

//执行条件引擎
void AdrTrigger::execTriggerEvent(const ProtoData &data)
{
    std::string topic = *data.topic.get();
    //从topic映射 的 事件ID里面 找出当前事件（即topic包含的信号在这个事件里面，这个在配置解析时加入），去掉不必要的其他事件判断循环
    std::vector<std::string> eventIDs = m_protoParse.m_topicEventIDList[topic];

    double currTime = Util::getMsTime();

    //一个topic可能在多个事件中
    for (size_t i = 0; i < eventIDs.size(); i++)
    {       
        std::string eventId = eventIDs.at(i);
        if (NotContain_Map(m_protoParse.m_protoRuleList, eventId))
        {
            continue;
        }
        std::shared_ptr<ProtoCondInfo_t> protoInfo = m_protoParse.m_protoRuleList[eventId];

        //判断开始提条件
        std::shared_ptr<ProtoCondRule_t> protoRule = protoInfo->rules;
        //是否有结束条件
        std::shared_ptr<ProtoCondRule_t> protoRuleEnd = protoInfo->rulesEnd;

        if(eventId=="BA844" || eventId == "BA015"){
            
            //所有信号满足条件
            TriggerEventInfo trigger;
            trigger.triggerTime = currTime;
            trigger.triggerStartTime =KTime::getPubTime();
            trigger.recordTime = CommonOprTime::getTime();
            trigger.eventName = protoInfo->eventName;
            trigger.status = protoInfo->status;
            trigger.beforeTime = protoInfo->beforeTime;
            trigger.laterTime = protoInfo->laterTime;
            trigger.collectDatas = protoInfo->collectData;
            trigger.level = protoInfo->level;

             DataCache::getInstance().acquireDataToSave(trigger);
        }


/*
        //先进行条件引擎判断；else进 特殊trigger判断
        if (protoInfo->specialRelatedTopic.size() == 0)
        {
            if (nullptr == protoRule)
            {
                Log_Info("checkTriggerEvent rull empty, topic: {}", topic);
                continue;
            }
            //非过程事件限制触发频率
            if (protoRuleEnd == nullptr)
            {
                if ((currTime - protoInfo->trigLaterTime) < protoInfo->limitTime)
                {
                    continue;
                }
            }

            if (TriggerStatus::TS_START != protoInfo->status)
            {
                if (!checkTriggerEvent(data, protoRule, protoInfo))
                { //没有触发
                    continue;
                }
                if (nullptr != protoRuleEnd)
                { //有结束条件
                    protoInfo->status = TriggerStatus::TS_START;
                }
                // protoInfo->trigLaterTime = currTime;                
            }
            else //条件状态为开始
            {
                if (nullptr == protoRuleEnd)
                {
                    Log_Info("protoRuleEnd rull empty, topic: {}", topic);
                    continue;
                }

                if (!checkTriggerEvent(data, protoRuleEnd, protoInfo)) //没有触发
                {
                    continue;
                }
                protoInfo->status = TriggerStatus::TS_END;
                // protoInfo->trigLaterTime = currTime;
            }

            //所有信号满足条件
            TriggerEventInfo trigger;
            trigger.triggerTime = currTime;
            trigger.triggerStartTime =KTime::getPubTime();
            trigger.recordTime = CommonOprTime::getTime();
            trigger.eventName = protoInfo->eventName;
            trigger.status = protoInfo->status;
            trigger.beforeTime = protoInfo->beforeTime;
            trigger.laterTime = protoInfo->laterTime;
            trigger.collectDatas = protoInfo->collectData;
            trigger.level = protoInfo->level;

            DataCache::getInstance().acquireDataToSave(trigger);
        }
*/
        else if (SpecialTrigger::getInstance().isContainTopic(topic))
        {
            //特殊写死trigger的判定
            SpecialTrigger::getInstance().inner_event_judge(data, protoInfo);
        }
    }
}


bool AdrTrigger::checkTriggerEvent(const ProtoData &data, std::shared_ptr<ProtoCondRule_t> protoRule, std::shared_ptr<ProtoCondInfo_t> protoInfo)
{
    (void)protoInfo;
    std::string topic = *data.topic.get();
    bool checkstate =false;
    string signalname = " ";
    //单个信号规则，进行一次普筛
    for (ProtoCondRuleSignalInfo_t &signal : protoRule->expressRule)
    {
        //当前topic信号，过滤其他信号
        if (signal.topic != topic)
        {
            // Log_Info("checkTriggerEvent rec topic: {}  conf topic: {}", topic, signal.topic);
            continue;
        };
        if(checkstate&& signalname == signal.name.back())
        {
            signal.changeOldValue = m_tmpSignalValue;
            continue;
        }
        if (checkTriggerEventSignal(data, signal))
        { //满足初步单个信号，判断其他所有信号，从缓存中取其他信号
            if (checkTriggerEventDetail(protoRule, signal.id, true))
            {
                //增加触发次数判断
                if (protoRule->triggerTimesExpect > 1)
                {
                    protoRule->triggerTimesReal++;
                    if (protoRule->triggerTimesReal < protoRule->triggerTimesExpect)
                    {
                        continue;
                    }
                    protoRule->triggerTimesReal = 0;
                }
                
                checkstate = true;
                signalname = signal.name.back();
            }
        }
    }
    return checkstate;
}

bool AdrTrigger::checkTriggerEventSignal(const ProtoData &data, ProtoCondRuleSignalInfo_t &signal)
{
    //动态解析数据
    uint8_t *buf = (uint8_t *)data.data.get()->c_str();
    std::string topic = *data.topic.get();
    //获取解析器
    google::protobuf::Message *parser = m_protoParse.getProtoMessageByTopic(topic);
    if (nullptr == parser)
    {
        Log_Info("Proto parser not found, topic: {}", topic);
        return false;
    }
    if (!parser->ParsePartialFromArray(buf, data._length))
    {
        Log_Info("Proto parse data failed, topic: {}", topic);
        return false;
    }
    //获取信号值,对比判断信号值
    bool ret{false};
    if ("bool" == signal.valueType)
    {
        ret = signalProcess<bool>(topic, signal, parser);
    }
    if ("double" == signal.valueType)
    {
        ret = signalProcess<double>(topic, signal, parser);
    }
    if ("string" == signal.valueType)
    {
        ret = signalProcess<string>(topic, signal, parser);
    }

    // 不存在时间要求
    if (signal.time == 0)
    {
        return ret;
    }

    ret = judgeDurationTime(data, signal, ret);

    //满足初步单个信号，判断其他所有信号，从缓存中取其他信号
    return ret;
}

template <typename classType>
bool AdrTrigger::signalProcess(const std::string &topic, ProtoCondRuleSignalInfo_t &signal, google::protobuf::Message *parser)
{
    (void)topic;
    classType signalValue = getProtoMessageMemberValue<classType>(*parser, signal.name);

    bool ret = compareSignalValue<classType>(signalValue, signal); //左区间判断
    // Log_Trig("Proto signal name: {}  signalValue: {}  compareValue: {}  opera: {} id: {}", signal.name.back(), signalValue, signal.constValue.toStyledString(), signal.opera, signal.id);
       
    signal.changeOldValue = signalValue;
    m_tmpSignalValue = signalValue;
    // Json::Value tmp;
    // string signame = Util::queueToString(signal.name);
    // tmp = signalValue;
    // m_lastValueData[signame] = tmp;

    return ret;
}

bool AdrTrigger::checkTriggerEventDetail(std::shared_ptr<ProtoCondRule_t> rule, const std::string &id, bool checkCurrentRule)
{
    //多个详细判断，默认由单次判断的规则进入则默认为true，如果是递归判断子规则则为false,

    for (int i = 0; i < rule->expressRule.size(); i++)
    {
        //如果为或条件又是true则直接break
        if (rule->expressRuleType == CondRuleType::CRT_OR && checkCurrentRule)
        {
            //或条件，一个成功即break
            break;
        }

        //判断每条子规则
        ProtoCondRuleSignalInfo_t &signal = rule->expressRule[i];
        //去掉当前信号，避免重复判断
        if (id == signal.id)
        {
            continue;
        }
        //取历史数据用来判断
        ProtoData pbData = DataCache::getInstance().getLastDataByTopic(signal.topic);
        //找不到历史数据
        if (nullptr == pbData.data)
        {
            Log_Info("ERROR history not found! topic: {}", signal.topic);
            return false;
        }
        bool ret = checkTriggerEventSignal(pbData, signal);
        //处理条件类型,从最小子集 往上发展。 比如A||（B&&C），应先计算B&&C
        if (rule->expressRuleType == CondRuleType::CRT_AND)
        {
            checkCurrentRule = (checkCurrentRule && ret);
            if (!checkCurrentRule)
            {
                //与条件，一个失败即break
                break;
            }
        }
        else if (rule->expressRuleType == CondRuleType::CRT_OR)
        {
            checkCurrentRule = (checkCurrentRule || ret);
            if (checkCurrentRule)
            {
                //或条件，一个成功即break
                break;
            }
        }
        else
        {
            Log_Info("ERROR rule type not correct! type: {}", rule->expressRuleType);
            return false;
        }
    }
    //是否有子规则，没有子规则，则当前规则的结果即为规则结果
    if (nullptr == rule->childRule)
    {
        return checkCurrentRule;
    }
    
    // 子规则内部判断条件为与，多个详细判断，默认由true进入。例如：1 & A & B 等价于 A & B
    // 子规则内部判断条件为或，多个详细判断，默认由false进入。例如：0 | A | B 等价于 A | B
    bool childRuleBool = (rule->childRule->expressRuleType == CondRuleType::CRT_AND) ? true : false;

    //有子规则，则当前规则 与子规则进行计算作为结果
    bool checkChildRule = checkTriggerEventDetail(rule->childRule, "-1", childRuleBool);
    if (rule->childRuleType == CondRuleType::CRT_AND)
    {
        return checkCurrentRule && checkChildRule;
    }
    else if (rule->childRuleType == CondRuleType::CRT_OR)
    {
        return checkCurrentRule || checkChildRule;
    }
    return false;
}

template <typename classType>
bool AdrTrigger::compareSignalValue(const classType &signalValue, const ProtoCondRuleSignalInfo_t &signal)
{
    classType compareValue = JsonToValue<classType>(signal.constValue);
    CondRuleCompareType type = signal.opera;

    switch (type)
    {
    case CondRuleCompareType::CRCT_NONE:
        return true;
        break;
    case CondRuleCompareType::CRCT_BIGER_THAN:
        if (signalValue > compareValue)
        {
            return true;
        }
        break;
    case CondRuleCompareType::CRCT_SMALLER_THAN:
        if (signalValue < compareValue)
        {
            return true;
        }
        break;
    case CondRuleCompareType::CRCT_EQUAL_THAN:
        {
            return (CompareValue(signalValue, compareValue) == CMP_EQUAL);
        }
        break;
    case CondRuleCompareType::CRCT_NOT_EQUAL:
        if (CompareValue(signalValue, compareValue) != CMP_EQUAL)
        {
            return true;
        }
        break;
    case CondRuleCompareType::CRCT_BIGER_EQUAL_THAN:
        if (signalValue >= compareValue)
        {
            return true;
        }
        break;
    case CondRuleCompareType::CRCT_SMALLER_EQUAL_THAN:
        if (signalValue <= compareValue)
        {
            return true;
        }
        break;
    case CondRuleCompareType::CRCT_CHANGE:
    {
        if (signal.changeVec.size() != 2 || signal.changeOldValue.isNull())
        {
            return false;
        }
        else
        {
            return (CompareValue(JsonToValue<classType>(signal.changeOldValue), JsonToValue<classType>(signal.changeVec.at(0))) == CMP_EQUAL) &&
                    (CompareValue(JsonToValue<classType>(signalValue), JsonToValue<classType>(signal.changeVec.at(1))) == CMP_EQUAL);
        }
        break;
    }
    case CondRuleCompareType::CRCT_CHANGE_NOTNOE2ONE:
    {
        if (signal.changeVec.size() != 2 || signal.changeOldValue.isNull())
        {
            return false;
        }
        else
        {
            return (CompareValue(JsonToValue<classType>(signal.changeOldValue), JsonToValue<classType>(signal.changeVec.at(0))) != CMP_EQUAL) &&
                    (CompareValue(JsonToValue<classType>(signalValue), JsonToValue<classType>(signal.changeVec.at(1))) == CMP_EQUAL);
        }
        break;
    }
    case CondRuleCompareType::CRCT_CHANGE_ONE2NOTNOE:
    {
        if (signal.changeVec.size() != 2 || signal.changeOldValue.isNull())
        {
            return false;
        }
        else
        {
            return (CompareValue(JsonToValue<classType>(signal.changeOldValue), JsonToValue<classType>(signal.changeVec.at(0))) == CMP_EQUAL) &&
                    (CompareValue(JsonToValue<classType>(signalValue), JsonToValue<classType>(signal.changeVec.at(1))) != CMP_EQUAL);
        }
        break;
    }
    default:
        break;
    }
    return false;
}

// 条件存在持续时间字段时进行判断
bool AdrTrigger::judgeDurationTime(const ProtoData &data, ProtoCondRuleSignalInfo_t &signal, bool ret)
{
    uint64_t time = data.time;

    // 跳变不支持
    CondRuleCompareType type = signal.opera;
    if (type == CRCT_CHANGE || type == CRCT_CHANGE_NOTNOE2ONE || type == CRCT_CHANGE_ONE2NOTNOE)
    {
        return ret;
    }

    // 信号值判断结果为false
    if (ret == false)
    {
        signal.beforeTimeStamp = 0;
        return ret;
    }

    // 是否是第一次信号值判断为true
    if (signal.beforeTimeStamp == 0)
    {
        signal.beforeTimeStamp = time;
        ret = false;
    }
    else
    {
        ret = (time - signal.beforeTimeStamp) > signal.time ? true : false;
    }
    return ret;
}
bool AdrTrigger::getOneEventProtoCondInfo(const string &eventId,std::shared_ptr<ProtoCondInfo_t> &protoCondInfo)
{
    if (NotContain_Map(m_protoParse.m_protoRuleList, eventId))
    {
        return false;
    }
    Log_Info("gd get {} collect size1:{}",eventId,m_protoParse.m_protoRuleList[eventId]->collectData.size());
    protoCondInfo = m_protoParse.m_protoRuleList[eventId];
    Log_Info("gd get {} collect size:{}",eventId,protoCondInfo->collectData.size());
    return true;  
}
